﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Keras.Models;
using Numpy;

namespace Keras.Helper
{
    /// <summary>
    /// 输入参数集合
    /// </summary>
    public class InputParamSet
    {
        /// <summary>
        /// 输入参数集合
        /// </summary>
        private List<InputParam> InputParamList { set; get; }

        /// <summary>
        /// 数据点数目
        /// </summary>
        public int Count
        {
            get
            {
                return this.InputParamList.Count;
            }
        }

        /// <summary>
        /// 转为数组
        /// </summary>
        /// <returns></returns>
        private double[,] GetArray()
        {
            //初始化
            double[,] dataArry = new double[this.Count, this.GetInputParamCount()];
            //遍历
            for (int index = 0; index < this.Count; index++)
            {
                var array = this.InputParamList[index].GetArray();
                for (int subIndex = 0; subIndex < array.Length; subIndex++)
                    dataArry[index, subIndex] = array[subIndex];
            }
            return dataArry;
        }

        /// <summary>
        /// 转为多维数组
        /// </summary>
        /// <returns></returns>
        public NDarray<double> GetNDsArray()
        {
            return np.array(this.GetArray());
        }

        /// <summary>
        /// 预测结果
        /// </summary>
        /// <param name="baseModel"></param>
        /// <returns></returns>
        public List<double> Predict(BaseModel baseModel)
        {
            //预测结果
            var value = baseModel.Predict(this.GetNDsArray());
            //获得所有结果
            var predictValues = value.GetData<float>().ToList().ConvertAll(f => (double)f);
            //确定预测的个数
            var predictNum = predictValues.Count / this.Count;
            //遍历
            for (int index = 0; index < this.Count; index++)
            {
                //初始化
                this.InputParamList[index].PredictValue = new List<double> (predictNum);
                //添加参数
                for (var predictID = 0; predictID < predictNum; predictID++)
                    this.InputParamList[index].PredictValue.Add(predictValues[index * predictNum + predictID]);
            }
                
            //获得所有数据
            return predictValues;
        }

        /// <summary>
        /// 预测结果
        /// </summary>
        /// <param name="baseModel"></param>
        /// <returns></returns>
        public List<double> Predict()
        {
            //创建神经网络
            var baseModel = KerasModel.GetBaseModel();
            //神经网络是否存在
            if (baseModel == null) return new List<double>();
            //返回预测结果
            return this.Predict(baseModel);
        }

        /// <summary>
        /// 预测结果
        /// 效率低 不推荐
        /// </summary>
        /// <param name="baseModel"></param>
        /// <returns></returns>
        public List<double> PredictOneByOne(BaseModel baseModel)
        {
            return new List<double>();
            //return (from param in this.InputParamList select param.Predict(baseModel)).ToList();
        }

        /// <summary>
        /// 添加值
        /// </summary>
        /// <param name="param"></param>
        public void Add(InputParam param)
        {
            this.InputParamList.Add(param);
        }

        /// <summary>
        /// 添加值
        /// </summary>
        /// <param name="variableList"></param>
        public void Add(List<double> variableList)
        {
            this.Add(new InputParam(variableList));
        }

        /// <summary>
        /// 输出层参数的数目
        /// </summary>
        /// <returns></returns>
        public int GetInputParamCount()
        {
            if (!this.isDataOkay()) return 0;
            else return this.InputParamList.First().Count;
        }

        /// <summary>
        /// 输出层参数需一致
        /// </summary>
        /// <returns></returns>
        public bool isDataOkay()
        {
            var valueList = (from param in this.InputParamList select param.Count).ToList();
            return valueList.Max() == valueList.Min();
        }

        /// <summary>
        /// 初始化
        /// </summary>
        public InputParamSet()
        {
            this.InputParamList = new List<InputParam>();
        }
    }
}
